library(here)
library(readxl)
library(dplyr)
library(BelgiumMaps.StatBel)
library(sf)
library(tmap)
library(leaflet)
library(leaflet.minicharts)
library(htmltools)
library(ggplot2)
library(stringr)
library(htmlwidgets)
library(here)

1 Read in dynam and spatial data

dynam.prov = read_excel(
    '20180425_dynam_be_jobdata_origineel.xlsx', 'Sheet2',
    skip = 1,  col_names = c(
      'province_lbl_nl', 'province_lbl_fr', 'province_nis_code', 
      'bruto_toename_absoluut', 'bruto_afname_absoluut', 'netto_absoluut', 'delme',
      'delmetoo', 'bruto_toename_graad', 'bruto_afname_graad', 'netto_graad', 'delmetootoo', 'werkzaamheidsgraad')) %>%
  select(-delme, -delmetoo, -delmetootoo)
dynam.prov
dynam.prov  <- dynam.prov %>% 
  mutate(
    province_lbl_nl = case_when(
      province_lbl_nl == 'Brussels Hoofdstedelijk Gewest' ~ 'Brussel',
      TRUE ~ province_lbl_nl))
dynam.prov = dynam.prov %>%
  mutate(
    province_lbl_pct = str_c(province_lbl_nl, '    ', str_sub(as.character(netto_graad*100),1,4), '%'))
province_lbl_ordered <- dynam.prov %>%
  arrange(netto_graad) %>% # rangschik procentuele of absolute groei
  # arrange(absoluut_netto) %>%
  pull(province_lbl_pct)
    
dynam.prov = dynam.prov %>%
    mutate(province_lbl_pct = factor(province_lbl_pct, levels = province_lbl_ordered))
dynam.prov = dynam.prov %>%
  mutate(
    netto_pct = netto_graad*100,
    bruto_toename_pct = bruto_toename_graad*100,
    bruto_afname_pct = bruto_afname_graad*100,
    bruto_afname_absoluut_neg = bruto_afname_absoluut*-1)
data('BE_ADMIN_PROVINCE') 
data("BE_ADMIN_REGION")
# convert to simple features dataset-structure
provinces = st_as_sf(BE_ADMIN_PROVINCE) 
regions = st_as_sf(BE_ADMIN_REGION) 
# Spatial object for Brussels-region is not included in provences, add from region
provinces = rbind(
  provinces %>% select(CD_PROV_REFNIS, TX_PROV_DESCR_NL),
  regions %>%
    filter(TX_RGN_DESCR_NL == "Brussels Hoofdstedelijk Gewest") %>%
    mutate(CD_RGN_REFNIS = '04000') %>%
    select(
      CD_PROV_REFNIS = CD_RGN_REFNIS,
      TX_PROV_DESCR_NL = TX_RGN_DESCR_NL))
provinces = provinces %>%
  mutate(CD_PROV_REFNIS = as.character(CD_PROV_REFNIS)) %>%
  left_join(dynam.prov, c('CD_PROV_REFNIS' = 'province_nis_code'))
# get centroid coordinates for each province to plot barchart there
provinces_coords = as_tibble(st_coordinates(st_centroid(provinces)))
names(provinces_coords) <- c('centroid_long', 'centroid_lat')
provinces <- bind_cols(provinces, provinces_coords)

2 Descriptive graphs

2.1 Overlapping barchart example

# Overlapping barcharts:
# http://stephanieevergreen.com/overlapping-bars/
# https://gist.github.com/hrbrmstr/035f998517de2384e9962cff7df874bd
# 
gg <- ggplot(data=dynam.prov, aes(y=province_lbl_pct, yend=province_lbl_pct))
gg <- gg + geom_segment(aes(x=bruto_afname_absoluut, xend=0, color="Jobverlies"), size=10)
gg <- gg + geom_segment(aes(x=bruto_toename_absoluut, xend=0, color="Jobgroei"), size=5)
gg <- gg + scale_x_continuous(labels=function(x) format(x, decimal.mark = ',', big.mark = ".", scientific = FALSE))
gg <- gg + scale_color_manual(name=NULL, values=c(Jobverlies="#bebebf", Jobgroei="#1074bc"))
gg <- gg + guides(color=guide_legend(keywidth=0, override.aes=list(size=4)))
gg <- gg + labs(
  x=NULL, y=NULL,
  title="Alle provincies kennen een netto jobaangroei, met de grootste\nprocentuele groei in Namen",
  subtitle = 'Procentuele en absolute jobevolutie per provincie, 2016-2017',
  caption="Bron: HIVA-KU Leuven | DynaM | dynamresearch.be")
gg <- gg + theme_minimal()
gg <- gg + theme(axis.text.x=element_text(margin=margin(t=0)))
gg <- gg + theme(axis.text.y=element_text(margin=margin(r=-10)))
gg <- gg + theme(panel.grid.minor=element_blank())
gg <- gg + theme(panel.grid.major.y=element_blank())
gg <- gg + theme(plot.title=element_text(face="bold"))
gg <- gg + theme(plot.margin=margin(20,20,20,20))
gg <- gg + theme(plot.caption=element_text(size=8, margin=margin(t=10, r=0)))
gg <- gg + theme(legend.position=c(0.8, 0.9))
gg <- gg + theme(legend.direction="vertical")
gg <- gg + theme(legend.background=element_rect(fill="white", color="white"))
gg

3 Static map visualisations

3.1 Inkleuren bruto toename

tm_shape(provinces) +
  tm_polygons(col = 'bruto_toename_pct', palette = 'Greens', border.col = 'white', title = 'Bruto jobtoename (%)')

3.2 Inkleuren bruto afname

tm_shape(provinces) +
  tm_polygons(col = 'bruto_afname_pct', palette = 'Reds', border.col = 'white', title = 'Bruto jobafname (%)')

3.3 Inkleuren netto evolutie

tm_shape(provinces) +
  tm_polygons(col = 'netto_pct', palette = 'Greens', border.col = 'white', title = 'Netto jobevolutie (%)')

3.4 Inkleuren bruto jobtoename + exact cijfer

tm_shape(provinces %>% mutate(bruto_toename_pct = as.character(round(bruto_toename_pct, 2)))) +
  tm_polygons(col = 'bruto_toename_pct', palette = 'Greens', border.col = 'white', title = 'Bruto jobtoename (%)') +
  tm_text('bruto_toename_pct', size= .7)

3.5 Inkleuren bruto jobafname + exact cijfer

tm_shape(provinces %>% mutate(bruto_afname_pct = round(bruto_afname_pct, 2))) +
  tm_polygons(col = 'bruto_afname_pct', palette = 'Reds', border.col = 'white', title = 'Bruto jobafname (%)') +
  tm_text('bruto_afname_pct', size= .7)

3.6 Inkleuren netto evolutie + exact cijfer

tm_shape(provinces %>% mutate(netto_pct = round(netto_pct, 2))) +
  tm_polygons(col = 'netto_pct', palette = 'Greens', border.col = 'white', title = 'Netto jobevolutie (%)') +
  tm_text('netto_pct', size= .7)

3.7 Inkleuren bruto + cijfers 1 digit + Nederlands

dynam.prov.bruto.nl = tm_shape(provinces %>% mutate(bruto_toename_pct_lbl = str_sub(as.character(bruto_toename_pct), 1,3))) +
  tm_polygons(col = 'bruto_toename_pct', palette = 'Greens', border.col = 'white', title = 'Bruto jobtoename (%)') +
  tm_text('bruto_toename_pct_lbl', size= .7)  +
  tm_layout(legend.format = list(text.separator = "-"), frame = FALSE)
dynam.prov.bruto.nl

3.8 Inkleuren bruto + cijfers 1 digit + Frans

dynam.prov.bruto.fr = tm_shape(provinces %>% mutate(bruto_toename_pct_lbl = str_sub(as.character(bruto_toename_pct), 1,3))) +
  tm_polygons(col = 'bruto_toename_pct', palette = 'Greens', border.col = 'white', title = 'Augmentation brute (%)') +
  tm_text('bruto_toename_pct_lbl', size= .7) +
  tm_layout(legend.format = list(text.separator = "à"), frame = FALSE)
dynam.prov.bruto.fr

4 Interactive map visualisations

labels_nl <- sprintf(
  "<strong>%s</strong><br/>Jobtoename: %1.2f%%<br/>Jobafname: %1.2f%%<br/>Netto evolutie: %1.2f%%<br/>",
  provinces$province_lbl_nl, provinces$bruto_toename_pct, provinces$bruto_afname_pct, provinces$netto_pct
) %>% lapply(htmltools::HTML)

4.1 Achtergrondkleur netto-evolutie (%) + cijfers in mouse-over popup

bins <- c(0.0, 0.5, 1, 1.5, 2.0, 2.5)
pal_greens_netto <- colorBin("Greens", domain = provinces$netto_pct, bins = bins)
# provinces <- provinces %>%
#   mutate(popup_lbl = str_glue("<h3>{province_lbl_nl}</h3><br /><b>Jobtoename: </b>{netto_pct}"))
map_title <- tags$div(
  HTML('<b>Netto jobevolutie per provincie, 2015-2016 (<a href="https://dynamresearch.be/">Dynam-Reg</a>)</b>')
)  
m.dynam.prov.netto.hover <- leaflet(provinces) %>%
  # setView(-96, 37.8, 4) %>%
  addPolygons(
    fillColor = ~pal_greens_netto(netto_pct),
    weight = 2,
    opacity = 1,
    color = "white",
    dashArray = "3",
    fillOpacity = 0.7,
    highlight = highlightOptions(
      weight = 5,
      color = "#666",
      dashArray = "",
      fillOpacity = 0.7,
      bringToFront = TRUE),
    label = labels_nl,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>%
  addLegend(
    title = 'Netto-jobevolutie (%)',
    pal = pal_greens_netto, values = ~netto_pct, opacity = 0.7,
            position = "topright") %>%
  addControl(map_title, position = "bottomleft")
m.dynam.prov.netto.hover

4.2 Achtergrondkleur bruto-toename (%) + cijfers in mouse-over popup + Nederlands

bins <- c(4, 5, 6, 7, 8)
pal_greens_toename <- colorBin("Greens", domain = provinces$bruto_toename_pct, bins = bins)
map_title <- tags$div(
  HTML('<b>Bruto jobtoename per provincie, 2015-2016 (<a href="http://www.dynam-belgium.org">Dynam-Reg</a>)</b>')
)
m.dynam.prov.toename.hover.nl <- leaflet(provinces) %>%
  # setView(-96, 37.8, 4) %>%
  addPolygons(
    fillColor = ~pal_greens_toename(bruto_toename_pct),
    weight = 2,
    opacity = 1,
    color = "white",
    dashArray = "3",
    fillOpacity = 0.7,
    highlight = highlightOptions(
      weight = 5,
      color = "#666",
      dashArray = "",
      fillOpacity = 0.7,
      bringToFront = TRUE),
    label = labels_nl,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>%
  addLegend(
    title = 'Bruto jobtoename (%)',
    pal = pal_greens_toename, values = ~bruto_toename_pct, opacity = 0.7,
            position = "topright") %>%
  addControl(map_title, position = "bottomleft")
m.dynam.prov.toename.hover.nl

4.3 Achtergrondkleur bruto-toename (%) + cijfers in mouse-over popup + Frans

bins <- c(4, 5, 6, 7, 8)
pal_greens_toename <- colorBin("Greens", domain = provinces$bruto_toename_pct, bins = bins)
labels_fr <- sprintf(
  "<strong>%s</strong><br/>Augmentation: %1.2f%%<br/>Diminution: %1.2f%%<br/>Evolution nette: %1.2f%%<br/>",
  provinces$province_lbl_fr, provinces$bruto_toename_pct, provinces$bruto_afname_pct, provinces$netto_pct
) %>% lapply(htmltools::HTML)
map_title <- tags$div(
  HTML('<b>Augmentation brute par province, 2015-2016 (<a href="http://www.dynam-belgium.org">Dynam-Reg</a>)</b>')
)
m.dynam.prov.toename.hover.fr <- leaflet(provinces) %>%
  # setView(-96, 37.8, 4) %>%
  addPolygons(
    fillColor = ~pal_greens_toename(bruto_toename_pct),
    weight = 2,
    opacity = 1,
    color = "white",
    dashArray = "3",
    fillOpacity = 0.7,
    highlight = highlightOptions(
      weight = 5,
      color = "#666",
      dashArray = "",
      fillOpacity = 0.7,
      bringToFront = TRUE),
    label = labels_fr,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>%
  addLegend(
    title = 'Augmentation brute (%)',
    pal = pal_greens_toename, values = ~bruto_toename_pct, opacity = 0.7,
            position = "topright") %>%
  addControl(map_title, position = "bottomleft")
m.dynam.prov.toename.hover.fr

4.4 Achtergrondkleur bruto-afname (%) + cijfers in mouse-over popup

bins <- c(4, 5, 6, 7, 8)
pal_greens_afname <- colorBin("Reds", domain = provinces$bruto_toename_pct, bins = bins)
map_title <- tags$div(
  HTML('<b>Bruto jobafname per provincie, 2015-2016 (<a href="https://dynamresearch.be/">dynaM</a>)</b>')
)
m.dynam.prov.afname.hover <- leaflet(provinces) %>%
  # setView(-96, 37.8, 4) %>%
  addPolygons(
    fillColor = ~pal_greens_afname(bruto_toename_pct),
    weight = 2,
    opacity = 1,
    color = "white",
    dashArray = "3",
    fillOpacity = 0.7,
    highlight = highlightOptions(
      weight = 5,
      color = "#666",
      dashArray = "",
      fillOpacity = 0.7,
      bringToFront = TRUE),
    label = labels_nl,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>%
  addLegend(
    title = 'Bruto jobafname (%)',
    pal = pal_greens_afname, values = ~bruto_toename_pct, opacity = 0.7,
            position = "topright") %>%
  addControl(map_title, position = "bottomleft")
m.dynam.prov.afname.hover

4.5 Achtergrondkleur netto-evolutie (%) + cijfers in mouse-over popup + netto-cijfer weergeven

bins <- c(0.0, 0.5, 1, 1.5, 2.0, 2.5)
pal_greens_netto <- colorBin("Greens", domain = provinces$netto_pct, bins = bins)
provinces <- provinces %>%
  mutate(popup_lbl = str_glue("<h3>{province_lbl_nl}</h3><br /><b>Jobtoename: </b>{netto_pct}"))
labels <- sprintf(
  "<strong>%s</strong><br/>Jobtoename: %1.2f%%<br/>Jobafname: %1.2f%%<br/>Netto evolutie: %1.2f%%<br/>",
  provinces$province_lbl_nl, provinces$bruto_toename_pct, provinces$bruto_afname_pct, provinces$netto_pct
) %>% lapply(htmltools::HTML)
map_title <- tags$div(
  HTML('<b>Netto jobevolutie per provincie, 2015-2016 (<a href="https://dynamresearch.be/">dynaM</a>)</b>')
)  
m.dynam.prov.netto.hover.number <- leaflet(provinces) %>%
  # setView(-96, 37.8, 4) %>%
  addPolygons(
    fillColor = ~pal_greens_netto(netto_pct),
    weight = 2,
    opacity = 1,
    color = "white",
    dashArray = "3",
    fillOpacity = 0.7,
    highlight = highlightOptions(
      weight = 5,
      color = "#666",
      dashArray = "",
      fillOpacity = 0.7,
      bringToFront = TRUE),
    label = labels_nl,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>%
  addLegend(
    title = 'Jobevolutie (%)',
    pal = pal_greens_netto, values = ~netto_pct, opacity = 0.7,
            position = "topright") %>%
  addControl(map_title, position = "bottomleft")
m.dynam.prov.netto.hover.number = m.dynam.prov.netto.hover.number %>%
  addLabelOnlyMarkers(lng = ~centroid_long, lat = ~centroid_lat, 
                      label =  ~as.character(round(netto_pct,2)), 
                      labelOptions = labelOptions(noHide = T, direction = 'top', textOnly = T))
m.dynam.prov.netto.hover.number

4.6 Achtergrond nettoevolutie + clickable barchart met absolute evolutie

pal <- colorBin("Greens", domain = dynam.prov$netto_pct)
d.abs = dynam.prov %>%
  select(
    'Jobgroei' = bruto_toename_absoluut,
    'Jobverlies' = bruto_afname_absoluut_neg,
    'Netto jobevolutie' = netto_absoluut)
d.pct = dynam.prov %>%
  mutate(
    bruto_toename_pct = round(bruto_toename_pct,2),
    bruto_afname_pct = round(bruto_afname_pct*-1,2),
    netto_pct = round(netto_pct,2)) %>%
select(
  'Jobgroei' = bruto_toename_pct,
  'Jobverlies' = bruto_afname_pct,
  'Netto jobevolutie' = netto_pct)
m.prov = leaflet(provinces, width = '100%') %>% 
  # add grey arrondissement polygons w/t white border
  addPolygons(
    weight = 2,
    opacity = 1,
    dashArray = "3",
    fillColor = ~pal(netto_pct), color = 'white') %>% 
  addLegend(pal = pal, values = ~netto_absoluut, opacity = 0.7,
            title = 'Netto jobevolutie (%)',
  position = "bottomright")
colors <- c("#7cae00", "#f8766d", "#c77cff")
m.prov = m.prov %>%
  addMinicharts(
    provinces_coords$centroid_long, provinces_coords$centroid_lat,
    chartdata = d.abs,
    colorPalette = colors,
    width = 45, height = 45)
map_title <- tags$div(
   HTML('<b>Bruto en netto jobevolutie per provincie, 2017-2018 (<a href="https://dynamresearch.be/">DynaM</a>)</b>')
 )  
m.prov = m.prov %>% 
  addControl(map_title, position = "bottomleft")
m.prov
m.dyam.bar.netto.pct = leaflet(provinces, width = '100%') %>% 
  # add grey arrondissement polygons w/t white border
  addPolygons(
    weight = 2,
    opacity = 1,
    dashArray = "3",
    fillColor = ~pal(netto_pct), color = 'white') %>% 
  addLegend(pal = pal, values = ~netto_pct, opacity = 0.7,
            title = 'Netto jobevolutie (%)',
  position = "bottomright")
colors <- c("#7cae00", "#f8766d", "#c77cff")
m.dyam.bar.netto.pct = m.dyam.bar.netto.pct %>%
  addMinicharts(
    provinces_coords$centroid_long, provinces_coords$centroid_lat,
    chartdata = d.pct,
    colorPalette = colors,
    width = 45, height = 45)
map_title <- tags$div(
   HTML('<b>Bruto en netto jobevolutie per provincie, 2017-2018 (<a href="https://dynamresearch.be/">DynaM</a>)</b>')
 )  
m.dyam.bar.netto.pct = m.dyam.bar.netto.pct %>% 
  addControl(map_title, position = "bottomleft")
m.dyam.bar.netto.pct
saveWidget(
  m.dynam.prov.toename.hover.nl, file = here::here(
    'dynam_jobevolution/maps_interactive', 'dynam_bruto_map_notselfcontained_nl.html'),
  selfcontained = FALSE,
  background = 'white')
saveWidget(
  m.dynam.prov.toename.hover.fr, file = here::here(
    'dynam_jobevolution/maps_interactive', 
    'dynam_bruto_map_notselfcontained_fr.html'),
  selfcontained = FALSE,
  background = 'white')
save_tmap(dynam.prov.bruto.nl, here::here('dynam_jobevolution/images', 'dynam_bruto_nl.png'))
save_tmap(dynam.prov.bruto.fr, here::here('dynam_jobevolution/images', 'dynam_bruto_fr.png'))

LS0tDQp0aXRsZTogIkR5bmFtIGpvYmV2b2x1dGllIGthYXJ0amVzIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazogDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0aGVtZTogbHVtZW4NCiAgICB0b2M6IHllcw0KLS0tDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShoZXJlKQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShCZWxnaXVtTWFwcy5TdGF0QmVsKQ0KbGlicmFyeShzZikNCmxpYnJhcnkodG1hcCkNCmxpYnJhcnkobGVhZmxldCkNCmxpYnJhcnkobGVhZmxldC5taW5pY2hhcnRzKQ0KbGlicmFyeShodG1sdG9vbHMpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KGh0bWx3aWRnZXRzKQ0KbGlicmFyeShoZXJlKQ0KYGBgDQoNCiMgUmVhZCBpbiBkeW5hbSBhbmQgc3BhdGlhbCBkYXRhDQoNCmBgYHtyfQ0KZHluYW0ucHJvdiA9IHJlYWRfZXhjZWwoDQogICAgJzIwMTgwNDI1X2R5bmFtX2JlX2pvYmRhdGFfb3JpZ2luZWVsLnhsc3gnLCAnU2hlZXQyJywNCiAgICBza2lwID0gMSwgIGNvbF9uYW1lcyA9IGMoDQogICAgICAncHJvdmluY2VfbGJsX25sJywgJ3Byb3ZpbmNlX2xibF9mcicsICdwcm92aW5jZV9uaXNfY29kZScsIA0KICAgICAgJ2JydXRvX3RvZW5hbWVfYWJzb2x1dXQnLCAnYnJ1dG9fYWZuYW1lX2Fic29sdXV0JywgJ25ldHRvX2Fic29sdXV0JywgJ2RlbG1lJywNCiAgICAgICdkZWxtZXRvbycsICdicnV0b190b2VuYW1lX2dyYWFkJywgJ2JydXRvX2FmbmFtZV9ncmFhZCcsICduZXR0b19ncmFhZCcsICdkZWxtZXRvb3RvbycsICd3ZXJremFhbWhlaWRzZ3JhYWQnKSkgJT4lDQogIHNlbGVjdCgtZGVsbWUsIC1kZWxtZXRvbywgLWRlbG1ldG9vdG9vKQ0KYGBgDQoNCmBgYHtyfQ0KZHluYW0ucHJvdg0KYGBgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KZHluYW0ucHJvdiAgPC0gZHluYW0ucHJvdiAlPiUgDQogIG11dGF0ZSgNCiAgICBwcm92aW5jZV9sYmxfbmwgPSBjYXNlX3doZW4oDQogICAgICBwcm92aW5jZV9sYmxfbmwgPT0gJ0JydXNzZWxzIEhvb2Zkc3RlZGVsaWprIEdld2VzdCcgfiAnQnJ1c3NlbCcsDQogICAgICBUUlVFIH4gcHJvdmluY2VfbGJsX25sKSkNCg0KZHluYW0ucHJvdiA9IGR5bmFtLnByb3YgJT4lDQogIG11dGF0ZSgNCiAgICBwcm92aW5jZV9sYmxfcGN0ID0gc3RyX2MocHJvdmluY2VfbGJsX25sLCAnICAgICcsIHN0cl9zdWIoYXMuY2hhcmFjdGVyKG5ldHRvX2dyYWFkKjEwMCksMSw0KSwgJyUnKSkNCg0KcHJvdmluY2VfbGJsX29yZGVyZWQgPC0gZHluYW0ucHJvdiAlPiUNCiAgYXJyYW5nZShuZXR0b19ncmFhZCkgJT4lICMgcmFuZ3NjaGlrIHByb2NlbnR1ZWxlIG9mIGFic29sdXRlIGdyb2VpDQogICMgYXJyYW5nZShhYnNvbHV1dF9uZXR0bykgJT4lDQogIHB1bGwocHJvdmluY2VfbGJsX3BjdCkNCg0KICAgIA0KZHluYW0ucHJvdiA9IGR5bmFtLnByb3YgJT4lDQogICAgbXV0YXRlKHByb3ZpbmNlX2xibF9wY3QgPSBmYWN0b3IocHJvdmluY2VfbGJsX3BjdCwgbGV2ZWxzID0gcHJvdmluY2VfbGJsX29yZGVyZWQpKQ0KDQpkeW5hbS5wcm92ID0gZHluYW0ucHJvdiAlPiUNCiAgbXV0YXRlKA0KICAgIG5ldHRvX3BjdCA9IG5ldHRvX2dyYWFkKjEwMCwNCiAgICBicnV0b190b2VuYW1lX3BjdCA9IGJydXRvX3RvZW5hbWVfZ3JhYWQqMTAwLA0KICAgIGJydXRvX2FmbmFtZV9wY3QgPSBicnV0b19hZm5hbWVfZ3JhYWQqMTAwLA0KICAgIGJydXRvX2FmbmFtZV9hYnNvbHV1dF9uZWcgPSBicnV0b19hZm5hbWVfYWJzb2x1dXQqLTEpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KZGF0YSgnQkVfQURNSU5fUFJPVklOQ0UnKSANCmRhdGEoIkJFX0FETUlOX1JFR0lPTiIpDQoNCiMgY29udmVydCB0byBzaW1wbGUgZmVhdHVyZXMgZGF0YXNldC1zdHJ1Y3R1cmUNCnByb3ZpbmNlcyA9IHN0X2FzX3NmKEJFX0FETUlOX1BST1ZJTkNFKSANCnJlZ2lvbnMgPSBzdF9hc19zZihCRV9BRE1JTl9SRUdJT04pIA0KDQojIFNwYXRpYWwgb2JqZWN0IGZvciBCcnVzc2Vscy1yZWdpb24gaXMgbm90IGluY2x1ZGVkIGluIHByb3ZlbmNlcywgYWRkIGZyb20gcmVnaW9uDQpwcm92aW5jZXMgPSByYmluZCgNCiAgcHJvdmluY2VzICU+JSBzZWxlY3QoQ0RfUFJPVl9SRUZOSVMsIFRYX1BST1ZfREVTQ1JfTkwpLA0KICByZWdpb25zICU+JQ0KICAgIGZpbHRlcihUWF9SR05fREVTQ1JfTkwgPT0gIkJydXNzZWxzIEhvb2Zkc3RlZGVsaWprIEdld2VzdCIpICU+JQ0KICAgIG11dGF0ZShDRF9SR05fUkVGTklTID0gJzA0MDAwJykgJT4lDQogICAgc2VsZWN0KA0KICAgICAgQ0RfUFJPVl9SRUZOSVMgPSBDRF9SR05fUkVGTklTLA0KICAgICAgVFhfUFJPVl9ERVNDUl9OTCA9IFRYX1JHTl9ERVNDUl9OTCkpDQpgYGANCg0KYGBge3J9DQpwcm92aW5jZXMgPSBwcm92aW5jZXMgJT4lDQogIG11dGF0ZShDRF9QUk9WX1JFRk5JUyA9IGFzLmNoYXJhY3RlcihDRF9QUk9WX1JFRk5JUykpICU+JQ0KICBsZWZ0X2pvaW4oZHluYW0ucHJvdiwgYygnQ0RfUFJPVl9SRUZOSVMnID0gJ3Byb3ZpbmNlX25pc19jb2RlJykpDQpgYGANCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgZ2V0IGNlbnRyb2lkIGNvb3JkaW5hdGVzIGZvciBlYWNoIHByb3ZpbmNlIHRvIHBsb3QgYmFyY2hhcnQgdGhlcmUNCnByb3ZpbmNlc19jb29yZHMgPSBhc190aWJibGUoc3RfY29vcmRpbmF0ZXMoc3RfY2VudHJvaWQocHJvdmluY2VzKSkpDQpuYW1lcyhwcm92aW5jZXNfY29vcmRzKSA8LSBjKCdjZW50cm9pZF9sb25nJywgJ2NlbnRyb2lkX2xhdCcpDQpwcm92aW5jZXMgPC0gYmluZF9jb2xzKHByb3ZpbmNlcywgcHJvdmluY2VzX2Nvb3JkcykNCmBgYA0KDQojIERlc2NyaXB0aXZlIGdyYXBocw0KDQojIyBPdmVybGFwcGluZyBiYXJjaGFydCBleGFtcGxlDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02LCBmaWcuYWxpZ249J2NlbnRlcid9DQojIE92ZXJsYXBwaW5nIGJhcmNoYXJ0czoNCiMgaHR0cDovL3N0ZXBoYW5pZWV2ZXJncmVlbi5jb20vb3ZlcmxhcHBpbmctYmFycy8NCiMgaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vaHJicm1zdHIvMDM1Zjk5ODUxN2RlMjM4NGU5OTYyY2ZmN2RmODc0YmQNCiMgDQoNCmdnIDwtIGdncGxvdChkYXRhPWR5bmFtLnByb3YsIGFlcyh5PXByb3ZpbmNlX2xibF9wY3QsIHllbmQ9cHJvdmluY2VfbGJsX3BjdCkpDQpnZyA8LSBnZyArIGdlb21fc2VnbWVudChhZXMoeD1icnV0b19hZm5hbWVfYWJzb2x1dXQsIHhlbmQ9MCwgY29sb3I9IkpvYnZlcmxpZXMiKSwgc2l6ZT0xMCkNCmdnIDwtIGdnICsgZ2VvbV9zZWdtZW50KGFlcyh4PWJydXRvX3RvZW5hbWVfYWJzb2x1dXQsIHhlbmQ9MCwgY29sb3I9IkpvYmdyb2VpIiksIHNpemU9NSkNCmdnIDwtIGdnICsgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscz1mdW5jdGlvbih4KSBmb3JtYXQoeCwgZGVjaW1hbC5tYXJrID0gJywnLCBiaWcubWFyayA9ICIuIiwgc2NpZW50aWZpYyA9IEZBTFNFKSkNCmdnIDwtIGdnICsgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9TlVMTCwgdmFsdWVzPWMoSm9idmVybGllcz0iI2JlYmViZiIsIEpvYmdyb2VpPSIjMTA3NGJjIikpDQpnZyA8LSBnZyArIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQoa2V5d2lkdGg9MCwgb3ZlcnJpZGUuYWVzPWxpc3Qoc2l6ZT00KSkpDQpnZyA8LSBnZyArIGxhYnMoDQogIHg9TlVMTCwgeT1OVUxMLA0KICB0aXRsZT0iQWxsZSBwcm92aW5jaWVzIGtlbm5lbiBlZW4gbmV0dG8gam9iYWFuZ3JvZWksIG1ldCBkZSBncm9vdHN0ZVxucHJvY2VudHVlbGUgZ3JvZWkgaW4gTmFtZW4iLA0KICBzdWJ0aXRsZSA9ICdQcm9jZW50dWVsZSBlbiBhYnNvbHV0ZSBqb2Jldm9sdXRpZSBwZXIgcHJvdmluY2llLCAyMDE2LTIwMTcnLA0KICBjYXB0aW9uPSJCcm9uOiBISVZBLUtVIExldXZlbiB8IER5bmFNIHwgZHluYW1yZXNlYXJjaC5iZSIpDQpnZyA8LSBnZyArIHRoZW1lX21pbmltYWwoKQ0KZ2cgPC0gZ2cgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQobWFyZ2luPW1hcmdpbih0PTApKSkNCmdnIDwtIGdnICsgdGhlbWUoYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KG1hcmdpbj1tYXJnaW4ocj0tMTApKSkNCmdnIDwtIGdnICsgdGhlbWUocGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCkpDQpnZyA8LSBnZyArIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueT1lbGVtZW50X2JsYW5rKCkpDQpnZyA8LSBnZyArIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSkNCmdnIDwtIGdnICsgdGhlbWUocGxvdC5tYXJnaW49bWFyZ2luKDIwLDIwLDIwLDIwKSkNCmdnIDwtIGdnICsgdGhlbWUocGxvdC5jYXB0aW9uPWVsZW1lbnRfdGV4dChzaXplPTgsIG1hcmdpbj1tYXJnaW4odD0xMCwgcj0wKSkpDQpnZyA8LSBnZyArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj1jKDAuOCwgMC45KSkNCmdnIDwtIGdnICsgdGhlbWUobGVnZW5kLmRpcmVjdGlvbj0idmVydGljYWwiKQ0KZ2cgPC0gZ2cgKyB0aGVtZShsZWdlbmQuYmFja2dyb3VuZD1lbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiLCBjb2xvcj0id2hpdGUiKSkNCmdnDQpgYGANCg0KIyBTdGF0aWMgbWFwIHZpc3VhbGlzYXRpb25zDQoNCiMjIElua2xldXJlbiBicnV0byB0b2VuYW1lDQoNCmBgYHtyfQ0KdG1fc2hhcGUocHJvdmluY2VzKSArDQogIHRtX3BvbHlnb25zKGNvbCA9ICdicnV0b190b2VuYW1lX3BjdCcsIHBhbGV0dGUgPSAnR3JlZW5zJywgYm9yZGVyLmNvbCA9ICd3aGl0ZScsIHRpdGxlID0gJ0JydXRvIGpvYnRvZW5hbWUgKCUpJykNCmBgYA0KDQojIyBJbmtsZXVyZW4gYnJ1dG8gYWZuYW1lDQoNCmBgYHtyfQ0KdG1fc2hhcGUocHJvdmluY2VzKSArDQogIHRtX3BvbHlnb25zKGNvbCA9ICdicnV0b19hZm5hbWVfcGN0JywgcGFsZXR0ZSA9ICdSZWRzJywgYm9yZGVyLmNvbCA9ICd3aGl0ZScsIHRpdGxlID0gJ0JydXRvIGpvYmFmbmFtZSAoJSknKQ0KYGBgDQoNCiMjIElua2xldXJlbiBuZXR0byBldm9sdXRpZQ0KDQpgYGB7cn0NCnRtX3NoYXBlKHByb3ZpbmNlcykgKw0KICB0bV9wb2x5Z29ucyhjb2wgPSAnbmV0dG9fcGN0JywgcGFsZXR0ZSA9ICdHcmVlbnMnLCBib3JkZXIuY29sID0gJ3doaXRlJywgdGl0bGUgPSAnTmV0dG8gam9iZXZvbHV0aWUgKCUpJykNCmBgYA0KDQojIyBJbmtsZXVyZW4gYnJ1dG8gam9idG9lbmFtZSArIGV4YWN0IGNpamZlcg0KDQpgYGB7cn0NCnRtX3NoYXBlKHByb3ZpbmNlcyAlPiUgbXV0YXRlKGJydXRvX3RvZW5hbWVfcGN0ID0gYXMuY2hhcmFjdGVyKHJvdW5kKGJydXRvX3RvZW5hbWVfcGN0LCAyKSkpKSArDQogIHRtX3BvbHlnb25zKGNvbCA9ICdicnV0b190b2VuYW1lX3BjdCcsIHBhbGV0dGUgPSAnR3JlZW5zJywgYm9yZGVyLmNvbCA9ICd3aGl0ZScsIHRpdGxlID0gJ0JydXRvIGpvYnRvZW5hbWUgKCUpJykgKw0KICB0bV90ZXh0KCdicnV0b190b2VuYW1lX3BjdCcsIHNpemU9IC43KQ0KYGBgDQoNCiMjIElua2xldXJlbiBicnV0byBqb2JhZm5hbWUgKyBleGFjdCBjaWpmZXINCg0KYGBge3J9DQp0bV9zaGFwZShwcm92aW5jZXMgJT4lIG11dGF0ZShicnV0b19hZm5hbWVfcGN0ID0gcm91bmQoYnJ1dG9fYWZuYW1lX3BjdCwgMikpKSArDQogIHRtX3BvbHlnb25zKGNvbCA9ICdicnV0b19hZm5hbWVfcGN0JywgcGFsZXR0ZSA9ICdSZWRzJywgYm9yZGVyLmNvbCA9ICd3aGl0ZScsIHRpdGxlID0gJ0JydXRvIGpvYmFmbmFtZSAoJSknKSArDQogIHRtX3RleHQoJ2JydXRvX2FmbmFtZV9wY3QnLCBzaXplPSAuNykNCmBgYA0KDQojIyBJbmtsZXVyZW4gbmV0dG8gZXZvbHV0aWUgKyBleGFjdCBjaWpmZXINCg0KYGBge3J9DQp0bV9zaGFwZShwcm92aW5jZXMgJT4lIG11dGF0ZShuZXR0b19wY3QgPSByb3VuZChuZXR0b19wY3QsIDIpKSkgKw0KICB0bV9wb2x5Z29ucyhjb2wgPSAnbmV0dG9fcGN0JywgcGFsZXR0ZSA9ICdHcmVlbnMnLCBib3JkZXIuY29sID0gJ3doaXRlJywgdGl0bGUgPSAnTmV0dG8gam9iZXZvbHV0aWUgKCUpJykgKw0KICB0bV90ZXh0KCduZXR0b19wY3QnLCBzaXplPSAuNykNCmBgYA0KDQojIyBJbmtsZXVyZW4gYnJ1dG8gKyBjaWpmZXJzIDEgZGlnaXQgKyBOZWRlcmxhbmRzDQoNCg0KYGBge3J9DQpkeW5hbS5wcm92LmJydXRvLm5sID0gdG1fc2hhcGUocHJvdmluY2VzICU+JSBtdXRhdGUoYnJ1dG9fdG9lbmFtZV9wY3RfbGJsID0gc3RyX3N1Yihhcy5jaGFyYWN0ZXIoYnJ1dG9fdG9lbmFtZV9wY3QpLCAxLDMpKSkgKw0KICB0bV9wb2x5Z29ucyhjb2wgPSAnYnJ1dG9fdG9lbmFtZV9wY3QnLCBwYWxldHRlID0gJ0dyZWVucycsIGJvcmRlci5jb2wgPSAnd2hpdGUnLCB0aXRsZSA9ICdCcnV0byBqb2J0b2VuYW1lICglKScpICsNCiAgdG1fdGV4dCgnYnJ1dG9fdG9lbmFtZV9wY3RfbGJsJywgc2l6ZT0gLjcpICArDQogIHRtX2xheW91dChsZWdlbmQuZm9ybWF0ID0gbGlzdCh0ZXh0LnNlcGFyYXRvciA9ICItIiksIGZyYW1lID0gRkFMU0UpDQpkeW5hbS5wcm92LmJydXRvLm5sDQpgYGANCg0KIyMgSW5rbGV1cmVuIGJydXRvICsgY2lqZmVycyAxIGRpZ2l0ICsgRnJhbnMNCg0KYGBge3J9DQpkeW5hbS5wcm92LmJydXRvLmZyID0gdG1fc2hhcGUocHJvdmluY2VzICU+JSBtdXRhdGUoYnJ1dG9fdG9lbmFtZV9wY3RfbGJsID0gc3RyX3N1Yihhcy5jaGFyYWN0ZXIoYnJ1dG9fdG9lbmFtZV9wY3QpLCAxLDMpKSkgKw0KICB0bV9wb2x5Z29ucyhjb2wgPSAnYnJ1dG9fdG9lbmFtZV9wY3QnLCBwYWxldHRlID0gJ0dyZWVucycsIGJvcmRlci5jb2wgPSAnd2hpdGUnLCB0aXRsZSA9ICdBdWdtZW50YXRpb24gYnJ1dGUgKCUpJykgKw0KICB0bV90ZXh0KCdicnV0b190b2VuYW1lX3BjdF9sYmwnLCBzaXplPSAuNykgKw0KICB0bV9sYXlvdXQobGVnZW5kLmZvcm1hdCA9IGxpc3QodGV4dC5zZXBhcmF0b3IgPSAiw6AiKSwgZnJhbWUgPSBGQUxTRSkNCmR5bmFtLnByb3YuYnJ1dG8uZnINCmBgYA0KDQojIEludGVyYWN0aXZlIG1hcCB2aXN1YWxpc2F0aW9ucw0KDQpgYGB7cn0NCmxhYmVsc19ubCA8LSBzcHJpbnRmKA0KICAiPHN0cm9uZz4lczwvc3Ryb25nPjxici8+Sm9idG9lbmFtZTogJTEuMmYlJTxici8+Sm9iYWZuYW1lOiAlMS4yZiUlPGJyLz5OZXR0byBldm9sdXRpZTogJTEuMmYlJTxici8+IiwNCiAgcHJvdmluY2VzJHByb3ZpbmNlX2xibF9ubCwgcHJvdmluY2VzJGJydXRvX3RvZW5hbWVfcGN0LCBwcm92aW5jZXMkYnJ1dG9fYWZuYW1lX3BjdCwgcHJvdmluY2VzJG5ldHRvX3BjdA0KKSAlPiUgbGFwcGx5KGh0bWx0b29sczo6SFRNTCkNCmBgYA0KDQoNCiMjIEFjaHRlcmdyb25ka2xldXIgbmV0dG8tZXZvbHV0aWUgKCUpICsgY2lqZmVycyBpbiBtb3VzZS1vdmVyIHBvcHVwDQoNCmBgYHtyfQ0KYmlucyA8LSBjKDAuMCwgMC41LCAxLCAxLjUsIDIuMCwgMi41KQ0KcGFsX2dyZWVuc19uZXR0byA8LSBjb2xvckJpbigiR3JlZW5zIiwgZG9tYWluID0gcHJvdmluY2VzJG5ldHRvX3BjdCwgYmlucyA9IGJpbnMpDQoNCiMgcHJvdmluY2VzIDwtIHByb3ZpbmNlcyAlPiUNCiMgICBtdXRhdGUocG9wdXBfbGJsID0gc3RyX2dsdWUoIjxoMz57cHJvdmluY2VfbGJsX25sfTwvaDM+PGJyIC8+PGI+Sm9idG9lbmFtZTogPC9iPntuZXR0b19wY3R9IikpDQoNCm1hcF90aXRsZSA8LSB0YWdzJGRpdigNCiAgSFRNTCgnPGI+TmV0dG8gam9iZXZvbHV0aWUgcGVyIHByb3ZpbmNpZSwgMjAxNS0yMDE2ICg8YSBocmVmPSJodHRwczovL2R5bmFtcmVzZWFyY2guYmUvIj5EeW5hbS1SZWc8L2E+KTwvYj4nKQ0KKSAgDQoNCm0uZHluYW0ucHJvdi5uZXR0by5ob3ZlciA8LSBsZWFmbGV0KHByb3ZpbmNlcykgJT4lDQogICMgc2V0VmlldygtOTYsIDM3LjgsIDQpICU+JQ0KICBhZGRQb2x5Z29ucygNCiAgICBmaWxsQ29sb3IgPSB+cGFsX2dyZWVuc19uZXR0byhuZXR0b19wY3QpLA0KICAgIHdlaWdodCA9IDIsDQogICAgb3BhY2l0eSA9IDEsDQogICAgY29sb3IgPSAid2hpdGUiLA0KICAgIGRhc2hBcnJheSA9ICIzIiwNCiAgICBmaWxsT3BhY2l0eSA9IDAuNywNCiAgICBoaWdobGlnaHQgPSBoaWdobGlnaHRPcHRpb25zKA0KICAgICAgd2VpZ2h0ID0gNSwNCiAgICAgIGNvbG9yID0gIiM2NjYiLA0KICAgICAgZGFzaEFycmF5ID0gIiIsDQogICAgICBmaWxsT3BhY2l0eSA9IDAuNywNCiAgICAgIGJyaW5nVG9Gcm9udCA9IFRSVUUpLA0KICAgIGxhYmVsID0gbGFiZWxzX25sLA0KICAgIGxhYmVsT3B0aW9ucyA9IGxhYmVsT3B0aW9ucygNCiAgICAgIHN0eWxlID0gbGlzdCgiZm9udC13ZWlnaHQiID0gIm5vcm1hbCIsIHBhZGRpbmcgPSAiM3B4IDhweCIpLA0KICAgICAgdGV4dHNpemUgPSAiMTVweCIsDQogICAgICBkaXJlY3Rpb24gPSAiYXV0byIpKSAlPiUNCiAgYWRkTGVnZW5kKA0KICAgIHRpdGxlID0gJ05ldHRvLWpvYmV2b2x1dGllICglKScsDQogICAgcGFsID0gcGFsX2dyZWVuc19uZXR0bywgdmFsdWVzID0gfm5ldHRvX3BjdCwgb3BhY2l0eSA9IDAuNywNCiAgICAgICAgICAgIHBvc2l0aW9uID0gInRvcHJpZ2h0IikgJT4lDQogIGFkZENvbnRyb2wobWFwX3RpdGxlLCBwb3NpdGlvbiA9ICJib3R0b21sZWZ0IikNCg0KbS5keW5hbS5wcm92Lm5ldHRvLmhvdmVyDQpgYGANCg0KIyMgQWNodGVyZ3JvbmRrbGV1ciBicnV0by10b2VuYW1lICglKSArIGNpamZlcnMgaW4gbW91c2Utb3ZlciBwb3B1cCArIE5lZGVybGFuZHMNCg0KYGBge3J9DQpiaW5zIDwtIGMoNCwgNSwgNiwgNywgOCkNCnBhbF9ncmVlbnNfdG9lbmFtZSA8LSBjb2xvckJpbigiR3JlZW5zIiwgZG9tYWluID0gcHJvdmluY2VzJGJydXRvX3RvZW5hbWVfcGN0LCBiaW5zID0gYmlucykNCg0KbWFwX3RpdGxlIDwtIHRhZ3MkZGl2KA0KICBIVE1MKCc8Yj5CcnV0byBqb2J0b2VuYW1lIHBlciBwcm92aW5jaWUsIDIwMTUtMjAxNiAoPGEgaHJlZj0iaHR0cDovL3d3dy5keW5hbS1iZWxnaXVtLm9yZyI+RHluYW0tUmVnPC9hPik8L2I+JykNCikNCg0KbS5keW5hbS5wcm92LnRvZW5hbWUuaG92ZXIubmwgPC0gbGVhZmxldChwcm92aW5jZXMpICU+JQ0KICAjIHNldFZpZXcoLTk2LCAzNy44LCA0KSAlPiUNCiAgYWRkUG9seWdvbnMoDQogICAgZmlsbENvbG9yID0gfnBhbF9ncmVlbnNfdG9lbmFtZShicnV0b190b2VuYW1lX3BjdCksDQogICAgd2VpZ2h0ID0gMiwNCiAgICBvcGFjaXR5ID0gMSwNCiAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgZGFzaEFycmF5ID0gIjMiLA0KICAgIGZpbGxPcGFjaXR5ID0gMC43LA0KICAgIGhpZ2hsaWdodCA9IGhpZ2hsaWdodE9wdGlvbnMoDQogICAgICB3ZWlnaHQgPSA1LA0KICAgICAgY29sb3IgPSAiIzY2NiIsDQogICAgICBkYXNoQXJyYXkgPSAiIiwNCiAgICAgIGZpbGxPcGFjaXR5ID0gMC43LA0KICAgICAgYnJpbmdUb0Zyb250ID0gVFJVRSksDQogICAgbGFiZWwgPSBsYWJlbHNfbmwsDQogICAgbGFiZWxPcHRpb25zID0gbGFiZWxPcHRpb25zKA0KICAgICAgc3R5bGUgPSBsaXN0KCJmb250LXdlaWdodCIgPSAibm9ybWFsIiwgcGFkZGluZyA9ICIzcHggOHB4IiksDQogICAgICB0ZXh0c2l6ZSA9ICIxNXB4IiwNCiAgICAgIGRpcmVjdGlvbiA9ICJhdXRvIikpICU+JQ0KICBhZGRMZWdlbmQoDQogICAgdGl0bGUgPSAnQnJ1dG8gam9idG9lbmFtZSAoJSknLA0KICAgIHBhbCA9IHBhbF9ncmVlbnNfdG9lbmFtZSwgdmFsdWVzID0gfmJydXRvX3RvZW5hbWVfcGN0LCBvcGFjaXR5ID0gMC43LA0KICAgICAgICAgICAgcG9zaXRpb24gPSAidG9wcmlnaHQiKSAlPiUNCiAgYWRkQ29udHJvbChtYXBfdGl0bGUsIHBvc2l0aW9uID0gImJvdHRvbWxlZnQiKQ0KDQptLmR5bmFtLnByb3YudG9lbmFtZS5ob3Zlci5ubA0KYGBgDQoNCiMjIEFjaHRlcmdyb25ka2xldXIgYnJ1dG8tdG9lbmFtZSAoJSkgKyBjaWpmZXJzIGluIG1vdXNlLW92ZXIgcG9wdXAgKyBGcmFucw0KDQpgYGB7cn0NCmJpbnMgPC0gYyg0LCA1LCA2LCA3LCA4KQ0KcGFsX2dyZWVuc190b2VuYW1lIDwtIGNvbG9yQmluKCJHcmVlbnMiLCBkb21haW4gPSBwcm92aW5jZXMkYnJ1dG9fdG9lbmFtZV9wY3QsIGJpbnMgPSBiaW5zKQ0KDQpsYWJlbHNfZnIgPC0gc3ByaW50ZigNCiAgIjxzdHJvbmc+JXM8L3N0cm9uZz48YnIvPkF1Z21lbnRhdGlvbjogJTEuMmYlJTxici8+RGltaW51dGlvbjogJTEuMmYlJTxici8+RXZvbHV0aW9uIG5ldHRlOiAlMS4yZiUlPGJyLz4iLA0KICBwcm92aW5jZXMkcHJvdmluY2VfbGJsX2ZyLCBwcm92aW5jZXMkYnJ1dG9fdG9lbmFtZV9wY3QsIHByb3ZpbmNlcyRicnV0b19hZm5hbWVfcGN0LCBwcm92aW5jZXMkbmV0dG9fcGN0DQopICU+JSBsYXBwbHkoaHRtbHRvb2xzOjpIVE1MKQ0KDQptYXBfdGl0bGUgPC0gdGFncyRkaXYoDQogIEhUTUwoJzxiPkF1Z21lbnRhdGlvbiBicnV0ZSBwYXIgcHJvdmluY2UsIDIwMTUtMjAxNiAoPGEgaHJlZj0iaHR0cDovL3d3dy5keW5hbS1iZWxnaXVtLm9yZyI+RHluYW0tUmVnPC9hPik8L2I+JykNCikNCg0KbS5keW5hbS5wcm92LnRvZW5hbWUuaG92ZXIuZnIgPC0gbGVhZmxldChwcm92aW5jZXMpICU+JQ0KICAjIHNldFZpZXcoLTk2LCAzNy44LCA0KSAlPiUNCiAgYWRkUG9seWdvbnMoDQogICAgZmlsbENvbG9yID0gfnBhbF9ncmVlbnNfdG9lbmFtZShicnV0b190b2VuYW1lX3BjdCksDQogICAgd2VpZ2h0ID0gMiwNCiAgICBvcGFjaXR5ID0gMSwNCiAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgZGFzaEFycmF5ID0gIjMiLA0KICAgIGZpbGxPcGFjaXR5ID0gMC43LA0KICAgIGhpZ2hsaWdodCA9IGhpZ2hsaWdodE9wdGlvbnMoDQogICAgICB3ZWlnaHQgPSA1LA0KICAgICAgY29sb3IgPSAiIzY2NiIsDQogICAgICBkYXNoQXJyYXkgPSAiIiwNCiAgICAgIGZpbGxPcGFjaXR5ID0gMC43LA0KICAgICAgYnJpbmdUb0Zyb250ID0gVFJVRSksDQogICAgbGFiZWwgPSBsYWJlbHNfZnIsDQogICAgbGFiZWxPcHRpb25zID0gbGFiZWxPcHRpb25zKA0KICAgICAgc3R5bGUgPSBsaXN0KCJmb250LXdlaWdodCIgPSAibm9ybWFsIiwgcGFkZGluZyA9ICIzcHggOHB4IiksDQogICAgICB0ZXh0c2l6ZSA9ICIxNXB4IiwNCiAgICAgIGRpcmVjdGlvbiA9ICJhdXRvIikpICU+JQ0KICBhZGRMZWdlbmQoDQogICAgdGl0bGUgPSAnQXVnbWVudGF0aW9uIGJydXRlICglKScsDQogICAgcGFsID0gcGFsX2dyZWVuc190b2VuYW1lLCB2YWx1ZXMgPSB+YnJ1dG9fdG9lbmFtZV9wY3QsIG9wYWNpdHkgPSAwLjcsDQogICAgICAgICAgICBwb3NpdGlvbiA9ICJ0b3ByaWdodCIpICU+JQ0KICBhZGRDb250cm9sKG1hcF90aXRsZSwgcG9zaXRpb24gPSAiYm90dG9tbGVmdCIpDQoNCm0uZHluYW0ucHJvdi50b2VuYW1lLmhvdmVyLmZyDQpgYGANCg0KIyMgQWNodGVyZ3JvbmRrbGV1ciBicnV0by1hZm5hbWUgKCUpICsgY2lqZmVycyBpbiBtb3VzZS1vdmVyIHBvcHVwDQoNCmBgYHtyfQ0KYmlucyA8LSBjKDQsIDUsIDYsIDcsIDgpDQpwYWxfZ3JlZW5zX2FmbmFtZSA8LSBjb2xvckJpbigiUmVkcyIsIGRvbWFpbiA9IHByb3ZpbmNlcyRicnV0b190b2VuYW1lX3BjdCwgYmlucyA9IGJpbnMpDQoNCm1hcF90aXRsZSA8LSB0YWdzJGRpdigNCiAgSFRNTCgnPGI+QnJ1dG8gam9iYWZuYW1lIHBlciBwcm92aW5jaWUsIDIwMTUtMjAxNiAoPGEgaHJlZj0iaHR0cHM6Ly9keW5hbXJlc2VhcmNoLmJlLyI+ZHluYU08L2E+KTwvYj4nKQ0KKQ0KDQptLmR5bmFtLnByb3YuYWZuYW1lLmhvdmVyIDwtIGxlYWZsZXQocHJvdmluY2VzKSAlPiUNCiAgIyBzZXRWaWV3KC05NiwgMzcuOCwgNCkgJT4lDQogIGFkZFBvbHlnb25zKA0KICAgIGZpbGxDb2xvciA9IH5wYWxfZ3JlZW5zX2FmbmFtZShicnV0b190b2VuYW1lX3BjdCksDQogICAgd2VpZ2h0ID0gMiwNCiAgICBvcGFjaXR5ID0gMSwNCiAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgZGFzaEFycmF5ID0gIjMiLA0KICAgIGZpbGxPcGFjaXR5ID0gMC43LA0KICAgIGhpZ2hsaWdodCA9IGhpZ2hsaWdodE9wdGlvbnMoDQogICAgICB3ZWlnaHQgPSA1LA0KICAgICAgY29sb3IgPSAiIzY2NiIsDQogICAgICBkYXNoQXJyYXkgPSAiIiwNCiAgICAgIGZpbGxPcGFjaXR5ID0gMC43LA0KICAgICAgYnJpbmdUb0Zyb250ID0gVFJVRSksDQogICAgbGFiZWwgPSBsYWJlbHNfbmwsDQogICAgbGFiZWxPcHRpb25zID0gbGFiZWxPcHRpb25zKA0KICAgICAgc3R5bGUgPSBsaXN0KCJmb250LXdlaWdodCIgPSAibm9ybWFsIiwgcGFkZGluZyA9ICIzcHggOHB4IiksDQogICAgICB0ZXh0c2l6ZSA9ICIxNXB4IiwNCiAgICAgIGRpcmVjdGlvbiA9ICJhdXRvIikpICU+JQ0KICBhZGRMZWdlbmQoDQogICAgdGl0bGUgPSAnQnJ1dG8gam9iYWZuYW1lICglKScsDQogICAgcGFsID0gcGFsX2dyZWVuc19hZm5hbWUsIHZhbHVlcyA9IH5icnV0b190b2VuYW1lX3BjdCwgb3BhY2l0eSA9IDAuNywNCiAgICAgICAgICAgIHBvc2l0aW9uID0gInRvcHJpZ2h0IikgJT4lDQogIGFkZENvbnRyb2wobWFwX3RpdGxlLCBwb3NpdGlvbiA9ICJib3R0b21sZWZ0IikNCg0KbS5keW5hbS5wcm92LmFmbmFtZS5ob3Zlcg0KYGBgDQoNCiMjIEFjaHRlcmdyb25ka2xldXIgbmV0dG8tZXZvbHV0aWUgKCUpICsgY2lqZmVycyBpbiBtb3VzZS1vdmVyIHBvcHVwICsgbmV0dG8tY2lqZmVyIHdlZXJnZXZlbg0KDQpgYGB7cn0NCmJpbnMgPC0gYygwLjAsIDAuNSwgMSwgMS41LCAyLjAsIDIuNSkNCnBhbF9ncmVlbnNfbmV0dG8gPC0gY29sb3JCaW4oIkdyZWVucyIsIGRvbWFpbiA9IHByb3ZpbmNlcyRuZXR0b19wY3QsIGJpbnMgPSBiaW5zKQ0KDQpwcm92aW5jZXMgPC0gcHJvdmluY2VzICU+JQ0KICBtdXRhdGUocG9wdXBfbGJsID0gc3RyX2dsdWUoIjxoMz57cHJvdmluY2VfbGJsX25sfTwvaDM+PGJyIC8+PGI+Sm9idG9lbmFtZTogPC9iPntuZXR0b19wY3R9IikpDQoNCmxhYmVscyA8LSBzcHJpbnRmKA0KICAiPHN0cm9uZz4lczwvc3Ryb25nPjxici8+Sm9idG9lbmFtZTogJTEuMmYlJTxici8+Sm9iYWZuYW1lOiAlMS4yZiUlPGJyLz5OZXR0byBldm9sdXRpZTogJTEuMmYlJTxici8+IiwNCiAgcHJvdmluY2VzJHByb3ZpbmNlX2xibF9ubCwgcHJvdmluY2VzJGJydXRvX3RvZW5hbWVfcGN0LCBwcm92aW5jZXMkYnJ1dG9fYWZuYW1lX3BjdCwgcHJvdmluY2VzJG5ldHRvX3BjdA0KKSAlPiUgbGFwcGx5KGh0bWx0b29sczo6SFRNTCkNCg0KbWFwX3RpdGxlIDwtIHRhZ3MkZGl2KA0KICBIVE1MKCc8Yj5OZXR0byBqb2Jldm9sdXRpZSBwZXIgcHJvdmluY2llLCAyMDE1LTIwMTYgKDxhIGhyZWY9Imh0dHBzOi8vZHluYW1yZXNlYXJjaC5iZS8iPmR5bmFNPC9hPik8L2I+JykNCikgIA0KDQptLmR5bmFtLnByb3YubmV0dG8uaG92ZXIubnVtYmVyIDwtIGxlYWZsZXQocHJvdmluY2VzKSAlPiUNCiAgIyBzZXRWaWV3KC05NiwgMzcuOCwgNCkgJT4lDQogIGFkZFBvbHlnb25zKA0KICAgIGZpbGxDb2xvciA9IH5wYWxfZ3JlZW5zX25ldHRvKG5ldHRvX3BjdCksDQogICAgd2VpZ2h0ID0gMiwNCiAgICBvcGFjaXR5ID0gMSwNCiAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgZGFzaEFycmF5ID0gIjMiLA0KICAgIGZpbGxPcGFjaXR5ID0gMC43LA0KICAgIGhpZ2hsaWdodCA9IGhpZ2hsaWdodE9wdGlvbnMoDQogICAgICB3ZWlnaHQgPSA1LA0KICAgICAgY29sb3IgPSAiIzY2NiIsDQogICAgICBkYXNoQXJyYXkgPSAiIiwNCiAgICAgIGZpbGxPcGFjaXR5ID0gMC43LA0KICAgICAgYnJpbmdUb0Zyb250ID0gVFJVRSksDQogICAgbGFiZWwgPSBsYWJlbHNfbmwsDQogICAgbGFiZWxPcHRpb25zID0gbGFiZWxPcHRpb25zKA0KICAgICAgc3R5bGUgPSBsaXN0KCJmb250LXdlaWdodCIgPSAibm9ybWFsIiwgcGFkZGluZyA9ICIzcHggOHB4IiksDQogICAgICB0ZXh0c2l6ZSA9ICIxNXB4IiwNCiAgICAgIGRpcmVjdGlvbiA9ICJhdXRvIikpICU+JQ0KICBhZGRMZWdlbmQoDQogICAgdGl0bGUgPSAnSm9iZXZvbHV0aWUgKCUpJywNCiAgICBwYWwgPSBwYWxfZ3JlZW5zX25ldHRvLCB2YWx1ZXMgPSB+bmV0dG9fcGN0LCBvcGFjaXR5ID0gMC43LA0KICAgICAgICAgICAgcG9zaXRpb24gPSAidG9wcmlnaHQiKSAlPiUNCiAgYWRkQ29udHJvbChtYXBfdGl0bGUsIHBvc2l0aW9uID0gImJvdHRvbWxlZnQiKQ0KDQptLmR5bmFtLnByb3YubmV0dG8uaG92ZXIubnVtYmVyID0gbS5keW5hbS5wcm92Lm5ldHRvLmhvdmVyLm51bWJlciAlPiUNCiAgYWRkTGFiZWxPbmx5TWFya2VycyhsbmcgPSB+Y2VudHJvaWRfbG9uZywgbGF0ID0gfmNlbnRyb2lkX2xhdCwgDQogICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAgfmFzLmNoYXJhY3Rlcihyb3VuZChuZXR0b19wY3QsMikpLCANCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMobm9IaWRlID0gVCwgZGlyZWN0aW9uID0gJ3RvcCcsIHRleHRPbmx5ID0gVCkpDQoNCm0uZHluYW0ucHJvdi5uZXR0by5ob3Zlci5udW1iZXINCg0KYGBgDQoNCg0KIyMgQWNodGVyZ3JvbmQgbmV0dG9ldm9sdXRpZSArIGNsaWNrYWJsZSBiYXJjaGFydCBtZXQgYWJzb2x1dGUgZXZvbHV0aWUgDQoNCmBgYHtyfQ0KcGFsIDwtIGNvbG9yQmluKCJHcmVlbnMiLCBkb21haW4gPSBkeW5hbS5wcm92JG5ldHRvX3BjdCkNCmBgYA0KDQoNCmBgYHtyfQ0KZC5hYnMgPSBkeW5hbS5wcm92ICU+JQ0KICBzZWxlY3QoDQogICAgJ0pvYmdyb2VpJyA9IGJydXRvX3RvZW5hbWVfYWJzb2x1dXQsDQogICAgJ0pvYnZlcmxpZXMnID0gYnJ1dG9fYWZuYW1lX2Fic29sdXV0X25lZywNCiAgICAnTmV0dG8gam9iZXZvbHV0aWUnID0gbmV0dG9fYWJzb2x1dXQpDQoNCmQucGN0ID0gZHluYW0ucHJvdiAlPiUNCiAgbXV0YXRlKA0KICAgIGJydXRvX3RvZW5hbWVfcGN0ID0gcm91bmQoYnJ1dG9fdG9lbmFtZV9wY3QsMiksDQogICAgYnJ1dG9fYWZuYW1lX3BjdCA9IHJvdW5kKGJydXRvX2FmbmFtZV9wY3QqLTEsMiksDQogICAgbmV0dG9fcGN0ID0gcm91bmQobmV0dG9fcGN0LDIpKSAlPiUNCnNlbGVjdCgNCiAgJ0pvYmdyb2VpJyA9IGJydXRvX3RvZW5hbWVfcGN0LA0KICAnSm9idmVybGllcycgPSBicnV0b19hZm5hbWVfcGN0LA0KICAnTmV0dG8gam9iZXZvbHV0aWUnID0gbmV0dG9fcGN0KQ0KYGBgDQoNCg0KYGBge3IgcmVzdWx0cz0iYXNpcyIsIGVjaG89RkFMU0V9DQpjYXQoIg0KPHN0eWxlPg0KLmxlYWZsZXQtY29udGFpbmVyIHsNCiAgICBiYWNrZ3JvdW5kOiAjRkZGOw0KfQ0KPC9zdHlsZT4NCiIpDQpgYGANCg0KYGBge3J9DQptLnByb3YgPSBsZWFmbGV0KHByb3ZpbmNlcywgd2lkdGggPSAnMTAwJScpICU+JSANCiAgIyBhZGQgZ3JleSBhcnJvbmRpc3NlbWVudCBwb2x5Z29ucyB3L3Qgd2hpdGUgYm9yZGVyDQogIGFkZFBvbHlnb25zKA0KICAgIHdlaWdodCA9IDIsDQogICAgb3BhY2l0eSA9IDEsDQogICAgZGFzaEFycmF5ID0gIjMiLA0KICAgIGZpbGxDb2xvciA9IH5wYWwobmV0dG9fcGN0KSwgY29sb3IgPSAnd2hpdGUnKSAlPiUgDQogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IH5uZXR0b19hYnNvbHV1dCwgb3BhY2l0eSA9IDAuNywNCiAgICAgICAgICAgIHRpdGxlID0gJ05ldHRvIGpvYmV2b2x1dGllICglKScsDQogIHBvc2l0aW9uID0gImJvdHRvbXJpZ2h0IikNCg0KY29sb3JzIDwtIGMoIiM3Y2FlMDAiLCAiI2Y4NzY2ZCIsICIjYzc3Y2ZmIikNCm0ucHJvdiA9IG0ucHJvdiAlPiUNCiAgYWRkTWluaWNoYXJ0cygNCiAgICBwcm92aW5jZXNfY29vcmRzJGNlbnRyb2lkX2xvbmcsIHByb3ZpbmNlc19jb29yZHMkY2VudHJvaWRfbGF0LA0KICAgIGNoYXJ0ZGF0YSA9IGQuYWJzLA0KICAgIGNvbG9yUGFsZXR0ZSA9IGNvbG9ycywNCiAgICB3aWR0aCA9IDQ1LCBoZWlnaHQgPSA0NSkNCg0KbWFwX3RpdGxlIDwtIHRhZ3MkZGl2KA0KICAgSFRNTCgnPGI+QnJ1dG8gZW4gbmV0dG8gam9iZXZvbHV0aWUgcGVyIHByb3ZpbmNpZSwgMjAxNy0yMDE4ICg8YSBocmVmPSJodHRwczovL2R5bmFtcmVzZWFyY2guYmUvIj5EeW5hTTwvYT4pPC9iPicpDQogKSAgDQoNCm0ucHJvdiA9IG0ucHJvdiAlPiUgDQogIGFkZENvbnRyb2wobWFwX3RpdGxlLCBwb3NpdGlvbiA9ICJib3R0b21sZWZ0IikNCg0KbS5wcm92DQoNCmBgYA0KDQoNCmBgYHtyfQ0KbS5keWFtLmJhci5uZXR0by5wY3QgPSBsZWFmbGV0KHByb3ZpbmNlcywgd2lkdGggPSAnMTAwJScpICU+JSANCiAgIyBhZGQgZ3JleSBhcnJvbmRpc3NlbWVudCBwb2x5Z29ucyB3L3Qgd2hpdGUgYm9yZGVyDQogIGFkZFBvbHlnb25zKA0KICAgIHdlaWdodCA9IDIsDQogICAgb3BhY2l0eSA9IDEsDQogICAgZGFzaEFycmF5ID0gIjMiLA0KICAgIGZpbGxDb2xvciA9IH5wYWwobmV0dG9fcGN0KSwgY29sb3IgPSAnd2hpdGUnKSAlPiUgDQogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IH5uZXR0b19wY3QsIG9wYWNpdHkgPSAwLjcsDQogICAgICAgICAgICB0aXRsZSA9ICdOZXR0byBqb2Jldm9sdXRpZSAoJSknLA0KICBwb3NpdGlvbiA9ICJib3R0b21yaWdodCIpDQoNCmNvbG9ycyA8LSBjKCIjN2NhZTAwIiwgIiNmODc2NmQiLCAiI2M3N2NmZiIpDQptLmR5YW0uYmFyLm5ldHRvLnBjdCA9IG0uZHlhbS5iYXIubmV0dG8ucGN0ICU+JQ0KICBhZGRNaW5pY2hhcnRzKA0KICAgIHByb3ZpbmNlc19jb29yZHMkY2VudHJvaWRfbG9uZywgcHJvdmluY2VzX2Nvb3JkcyRjZW50cm9pZF9sYXQsDQogICAgY2hhcnRkYXRhID0gZC5wY3QsDQogICAgY29sb3JQYWxldHRlID0gY29sb3JzLA0KICAgIHdpZHRoID0gNDUsIGhlaWdodCA9IDQ1KQ0KDQptYXBfdGl0bGUgPC0gdGFncyRkaXYoDQogICBIVE1MKCc8Yj5CcnV0byBlbiBuZXR0byBqb2Jldm9sdXRpZSBwZXIgcHJvdmluY2llLCAyMDE3LTIwMTggKDxhIGhyZWY9Imh0dHBzOi8vZHluYW1yZXNlYXJjaC5iZS8iPkR5bmFNPC9hPik8L2I+JykNCiApICANCg0KbS5keWFtLmJhci5uZXR0by5wY3QgPSBtLmR5YW0uYmFyLm5ldHRvLnBjdCAlPiUgDQogIGFkZENvbnRyb2wobWFwX3RpdGxlLCBwb3NpdGlvbiA9ICJib3R0b21sZWZ0IikNCg0KbS5keWFtLmJhci5uZXR0by5wY3QNCg0KYGBgDQoNCmBgYHtyfQ0Kc2F2ZVdpZGdldCgNCiAgbS5keW5hbS5wcm92LnRvZW5hbWUuaG92ZXIubmwsIGZpbGUgPSBoZXJlOjpoZXJlKA0KICAgICdkeW5hbV9qb2Jldm9sdXRpb24vbWFwc19pbnRlcmFjdGl2ZScsICdkeW5hbV9icnV0b19tYXBfbm90c2VsZmNvbnRhaW5lZF9ubC5odG1sJyksDQogIHNlbGZjb250YWluZWQgPSBGQUxTRSwNCiAgYmFja2dyb3VuZCA9ICd3aGl0ZScpDQoNCnNhdmVXaWRnZXQoDQogIG0uZHluYW0ucHJvdi50b2VuYW1lLmhvdmVyLmZyLCBmaWxlID0gaGVyZTo6aGVyZSgNCiAgICAnZHluYW1fam9iZXZvbHV0aW9uL21hcHNfaW50ZXJhY3RpdmUnLCANCiAgICAnZHluYW1fYnJ1dG9fbWFwX25vdHNlbGZjb250YWluZWRfZnIuaHRtbCcpLA0KICBzZWxmY29udGFpbmVkID0gRkFMU0UsDQogIGJhY2tncm91bmQgPSAnd2hpdGUnKQ0KYGBgDQoNCmBgYHtyfQ0Kc2F2ZV90bWFwKGR5bmFtLnByb3YuYnJ1dG8ubmwsIGhlcmU6OmhlcmUoJ2R5bmFtX2pvYmV2b2x1dGlvbi9pbWFnZXMnLCAnZHluYW1fYnJ1dG9fbmwucG5nJykpDQpzYXZlX3RtYXAoZHluYW0ucHJvdi5icnV0by5mciwgaGVyZTo6aGVyZSgnZHluYW1fam9iZXZvbHV0aW9uL2ltYWdlcycsICdkeW5hbV9icnV0b19mci5wbmcnKSkNCmBgYA0KDQo=